package com.appointment.utils.Jwt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Component
public class JwtUtil {
    // 设置token的密钥
    @Value("${jwt.secret}")
    private String secret;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private Key key;

    @PostConstruct
    public void init() {
        key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 生成token
     *
     * @param id   角色id
     * @param role 角色
     * @return token
     */
    public String generateToken(String id, String role) {
        if (id == null || role == null) {
            throw new IllegalArgumentException("id和role不能为空");
        }
        if (!JwtRoles.checkRole(role)) {
            throw new IllegalArgumentException("角色不存在");
        }
        Date now = new Date();
        Date expirationDate = new Date(now.getTime() + JwtRoles.getExpireTime(role));
        // 设置一些令牌属性，如用户id、签发时间、过期时间、签名和最终的字符串
        return Jwts.builder()
                .setSubject(id)
                .claim("role", role)
                .claim("createTime", now)
                .setIssuedAt(now)
                .setExpiration(expirationDate)
                .signWith(key)
                .compact();
    }

    /**
     * 验证token
     *
     * @param token token
     * @return 是否有效
     */
    public boolean validateToken(String token) {
        if (token == null) {
            return false;
        }
        try {
            Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 从token中获取id
     *
     * @param token token
     * @return id
     */
    public String getIdFromToken(String token) {
        if (token == null) {
            throw new IllegalArgumentException("token不能为空");
        }
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }

    /**
     * 从token中获取role
     *
     * @param token token
     * @return role
     */
    public String getRoleFromToken(String token) {
        if (token == null) {
            throw new IllegalArgumentException("token不能为空");
        }
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
        return (String) claims.get("role");
    }

    /**
     * 从token中获取创建时间
     *
     * @param token token
     * @return 创建时间
     */
    public Long getCreateTimeFromToken(String token) {
        if (token == null) {
            throw new IllegalArgumentException("token不能为空");
        }
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
        Long createTime = claims.get("createTime", Long.class);
        if (createTime == null) {
            throw new IllegalArgumentException("token不包含创建时间");
        }
        return createTime;
    }

    /**
     * 添加token到黑名单
     *
     * @param token token
     */
    public boolean addBlackList(String token) {
        if (token == null) {
            throw new IllegalArgumentException("token不能为空");
        }
        if (validateToken(token)) {
            long blackListTime = getRemainingTime(token);
            redisTemplate.opsForValue().set(token, "blackList", blackListTime, TimeUnit.MILLISECONDS);
            return true;
        }
        return false;
    }

    /**
     * 判断token是否在黑名单中
     *
     * @param token token
     * @return 是否在黑名单中
     */
    public boolean isBlackList(String token) {
        if (token == null) {
            throw new IllegalArgumentException("token不能为空");
        }
        return Boolean.TRUE.equals(redisTemplate.hasKey(token));
    }

    /**
     * 获取token的剩余有效时间
     *
     * @param token token
     * @return 剩余有效时间
     */
    public long getRemainingTime(String token) {
        if (token == null) {
            throw new IllegalArgumentException("token不能为空");
        }
        if (isBlackList(token)) {
            return 0;
        }
        long createTime = getCreateTimeFromToken(token);
        long expireTime = JwtRoles.getExpireTime(getRoleFromToken(token));
        return expireTime - (System.currentTimeMillis() - createTime);
    }
}